home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / compress / gnucpio.zip / TCEXPARG.C < prev    next >
C/C++ Source or Header  |  1994-12-01  |  6KB  |  241 lines

  1. /* tcexparg.c - Unix-style command line wildcards for Turbo C 2.0
  2.  
  3.    This file is in the public domain.
  4.  
  5.    Compile your main program with -Dmain=_main and link with this file.
  6.  
  7.    After that, it is just as if the operating system had expanded the
  8.    arguments, except that they are not sorted.  The program name and all
  9.    arguments that are expanded from wildcards are lowercased.
  10.  
  11.    Syntax for wildcards:
  12.    *        Matches zero or more of any character (except a '.' at
  13.         the beginning of a name).
  14.    ?        Matches any single character.
  15.    [r3z]    Matches 'r', '3', or 'z'.
  16.    [a-d]    Matches a single character in the range 'a' through 'd'.
  17.    [!a-d]    Matches any single character except a character in the
  18.         range 'a' through 'd'.
  19.  
  20.    The period between the filename root and its extension need not be
  21.    given explicitly.  Thus, the pattern `a*e' will match 'abacus.exe'
  22.    and 'axyz.e' as well as 'apple'.  Comparisons are not case sensitive.
  23.  
  24.    Authors:
  25.    The expargs code is a modification of wildcard expansion code
  26.    written for Turbo C 1.0 by
  27.    Richard Hargrove
  28.    Texas Instruments, Inc.
  29.    P.O. Box 869305, m/s 8473
  30.    Plano, Texas 75086
  31.    214/575-4128
  32.    and posted to USENET in September, 1987.
  33.  
  34.    The wild_match code was written by Rich Salz, rsalz@bbn.com,
  35.    posted to net.sources in November, 1986.
  36.  
  37.    The code connecting the two is by Mike Slomin, bellcore!lcuxa!mike2,
  38.    posted to comp.sys.ibm.pc in November, 1988.
  39.  
  40.    Major performance enhancements and bug fixes, and source cleanup,
  41.    by David MacKenzie, djm@gnu.ai.mit.edu.  */
  42.  
  43. #include <stdio.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #include <dos.h>
  47. #include <dir.h>
  48.  
  49. /* Number of new arguments to allocate space for at a time.  */
  50. #define ARGS_INCREMENT 10
  51.  
  52. /* The name this program was run with, for error messages.  */
  53. static char *program_name;
  54.  
  55. static char **grow_argv (char **new_argv, int new_argc);
  56. static void fatal_error (const char *message);
  57.  
  58. int wild_match (char *string, char *pattern);
  59. char *basename (char *path);
  60.  
  61. char **expargs (int *, char **);
  62.  
  63. #ifdef main
  64. #undef main
  65. #endif
  66.  
  67. int
  68. main (int argc, char **argv, char **envp)
  69. {
  70.   argv = expargs (&argc, argv);
  71.   return _main (argc, argv, envp);
  72. }
  73.  
  74. char **
  75. expargs (int *pargc, char **argv)
  76. {
  77.   char path[MAXPATH + 1];
  78.   char **new_argv;
  79.   struct ffblk block;
  80.   char *path_base;
  81.   char *arg_base;
  82.   int argind;
  83.   int new_argc;
  84.   int path_length;
  85.   int matched;
  86.  
  87.   program_name = argv[0];
  88.   if (program_name && *program_name)
  89.     strlwr (program_name);
  90.   new_argv = grow_argv (NULL, 0);
  91.   new_argv[0] = argv[0];
  92.   new_argc = 1;
  93.  
  94.   for (argind = 1; argind < *pargc; ++argind)
  95.     {
  96.       matched = 0;
  97.       if (strpbrk (argv[argind], "?*[") != NULL)
  98.     {
  99.       strncpy (path, argv[argind], MAXPATH - 3);
  100.       path_base = basename (path);
  101.       strcpy (path_base, "*.*");
  102.       arg_base = argv[argind] + (path_base - path);
  103.  
  104.       if (!findfirst (path, &block, FA_DIREC))
  105.         {
  106.           strlwr (path);
  107.           do
  108.         {
  109.           /* Only match "." and ".." explicitly.  */
  110.           if (*block.ff_name == '.' && *arg_base != '.')
  111.             continue;
  112.           path_length = stpcpy (path_base, block.ff_name) - path + 1;
  113.           strlwr (path_base);
  114.           if (wild_match (path, argv[argind]))
  115.             {
  116.               matched = 1;
  117.               new_argv[new_argc] = (char *) malloc (path_length);
  118.               if (new_argv[new_argc] == NULL)
  119.             fatal_error ("memory exhausted");
  120.               strcpy (new_argv[new_argc++], path);
  121.               new_argv = grow_argv (new_argv, new_argc);
  122.             }
  123.           } while (!findnext (&block));
  124.         }
  125.     }
  126.       if (matched == 0)
  127.     new_argv[new_argc++] = argv[argind];
  128.       new_argv = grow_argv (new_argv, new_argc);
  129.     }
  130.  
  131.   *pargc = new_argc;
  132.   new_argv[new_argc] = NULL;
  133.   return &new_argv[0];
  134. }
  135.  
  136. /* Return a pointer to the last element of PATH.  */
  137.  
  138. char *
  139. basename (char *path)
  140. {
  141.   char *tail;
  142.  
  143.   for (tail = path; *path; ++path)
  144.     if (*path == ':' || *path == '\\')
  145.       tail = path + 1;
  146.   return tail;
  147. }
  148.  
  149. static char **
  150. grow_argv (char **new_argv, int new_argc)
  151. {
  152.   if (new_argc % ARGS_INCREMENT == 0)
  153.     {
  154.       new_argv = (char **) realloc
  155.     (new_argv, sizeof (char *) * (new_argc + ARGS_INCREMENT));
  156.       if (new_argv == NULL)
  157.     fatal_error ("memory exhausted");
  158.     }
  159.   return new_argv;
  160. }
  161.  
  162. static void
  163. fatal_error (const char *message)
  164. {
  165.   putc ('\n', stderr);
  166.   if (program_name && *program_name)
  167.     {
  168.       fputs (program_name, stderr);
  169.       fputs (": ", stderr);
  170.     }
  171.   fputs (message, stderr);
  172.   putc ('\n', stderr);
  173.   exit (1);
  174. }
  175.  
  176. /* Shell-style pattern matching for ?, \, [], and * characters.
  177.    I'm putting this replacement in the public domain.
  178.  
  179.    Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.  */
  180.  
  181. /* The character that inverts a character class; '!' or '^'.  */
  182. #define INVERT '!'
  183.  
  184. static int star (char *string, char *pattern);
  185.  
  186. /* Return nonzero if `string' matches Unix-style wildcard pattern
  187.    `pattern'; zero if not.  */
  188.  
  189. int
  190. wild_match (char *string, char *pattern)
  191. {
  192.   int prev;        /* Previous character in character class.  */
  193.   int matched;        /* If 1, character class has been matched.  */
  194.   int reverse;        /* If 1, character class is inverted.  */
  195.  
  196.   for (; *pattern; string++, pattern++)
  197.     switch (*pattern)
  198.       {
  199.       case '\\':
  200.     /* Literal match with following character; fall through.  */
  201.     pattern++;
  202.       default:
  203.     if (*string != *pattern)
  204.       return 0;
  205.     continue;
  206.       case '?':
  207.     /* Match anything.  */
  208.     if (*string == '\0')
  209.       return 0;
  210.     continue;
  211.       case '*':
  212.     /* Trailing star matches everything.  */
  213.     return *++pattern ? star (string, pattern) : 1;
  214.       case '[':
  215.     /* Check for inverse character class.  */
  216.     reverse = pattern[1] == INVERT;
  217.     if (reverse)
  218.       pattern++;
  219.     for (prev = 256, matched = 0; *++pattern && *pattern != ']';
  220.          prev = *pattern)
  221.       if (*pattern == '-'
  222.           ? *string <= *++pattern && *string >= prev
  223.           : *string == *pattern)
  224.         matched = 1;
  225.     if (matched == reverse)
  226.       return 0;
  227.     continue;
  228.       }
  229.  
  230.   return *string == '\0';
  231. }
  232.  
  233. static int
  234. star (char *string, char *pattern)
  235. {
  236.   while (wild_match (string, pattern) == 0)
  237.     if (*++string == '\0')
  238.       return 0;
  239.   return 1;
  240. }
  241.